#include "Picker.h"

#include "Model3D.h"
#include "IObjectForPicker.h"
//map of Model3D pointers and Positions of this models


Picker::Picker()
  : m_for_picking()
  {

  }

size_t Picker::AddObject(const IObjectForPicker* ip_object, TVector3 i_position)
  {
  m_for_picking.push_back(std::make_pair(ip_object, i_position));
  return m_for_picking.size() - 1;
  }


bool Picker::GetIntersectionTriangle(TTriangle3& o_triangle, const TRay3& i_ray) const
  {
  size_t id = 0;
  return _GetIntersectionInfo(o_triangle, id, i_ray);
  }

bool Picker::GetIntersectionModelId(size_t& o_index, const TRay3& i_ray) const
  {
  TTriangle3 triangle;
  return _GetIntersectionInfo(triangle, o_index, i_ray);
  }

bool Picker::GetIntersectionPoint(TVector3& o_result, const TRay3& i_ray) const
  {
  TTriangle3 triangle;
  size_t id = 0;
  bool has_intersection = _GetIntersectionInfo(triangle, id, i_ray);
  ::GetIntersectionPoint(o_result, triangle, i_ray);

  return has_intersection;
  }

bool Picker::_GetIntersectionTriangle(TTriangle3& o_triangle, const IObjectForPicker* i_object, const TVector3& i_origin, const TRay3& i_ray) const
{
  auto line = TLine3(i_ray.Origin - i_origin, i_ray.Direction);

  bool has_intersection = false;
  auto triangles = i_object->PickTriangles(line);
  for (size_t i = 0; i < triangles.size(); i++)
    {
    TVector3 point;
    TVector3 result;
    if (::GetIntersectionPoint(point, triangles[i], i_ray))
      {
      point += i_origin;
      if (!has_intersection)
        {
        o_triangle = triangles[i];
        result = point;
        }
      else if (GetDistanceBetweenPoints(point, i_ray.Origin) < GetDistanceBetweenPoints(result, i_ray.Origin))
        {
        o_triangle = triangles[i];
        result = point;
        }
      has_intersection = true;
      }
    }
  return has_intersection;
  }



bool Picker::_GetIntersectionInfo(TTriangle3& o_triangle, size_t& o_index, const TRay3& i_ray) const
  {
  bool is_first = true;
  bool has_intersection = false;

  for(size_t index = 0; index < m_for_picking.size(); ++index)
    {
    TVector3 point;
    if(is_first == true)
      {
      has_intersection = _GetIntersectionTriangle(o_triangle, m_for_picking[index].first, m_for_picking[index].second, i_ray);

      if (has_intersection)
        {
        is_first = false;
        o_index = index;
        }        
      }

    if (has_intersection && !is_first)
      {
      TTriangle3 temp_triangle;

      if (_GetIntersectionTriangle(temp_triangle, m_for_picking[index].first, m_for_picking[index].second, i_ray))
        {
        TVector3 point1;
        ::GetIntersectionPoint(point1, o_triangle, i_ray);
        TVector3 point2;
        ::GetIntersectionPoint(point2, temp_triangle, i_ray);

        if (GetDistanceBetweenPoints(point1, i_ray.Origin) >= GetDistanceBetweenPoints(point2, i_ray.Origin))
          {
          o_triangle.V[0] = temp_triangle.V[0];
          o_triangle.V[1] = temp_triangle.V[1];
          o_triangle.V[2] = temp_triangle.V[2];

          o_index = index;
          }
        }
      }
    }
  return has_intersection;
  }

